<template>
  <el-dialog
    v-model="visible"
    fullscreen
    destroy-on-close
  >
    <div class="studioView" ref="studioViewRef">
      <div v-show="state.pageShow" >
        <resp-list ref="respListRef" @openRepository="openRepository_"></resp-list>
      </div>
      <!-- 打开弹框 -->
      <!-- ==============================操作模块========================================== -->
      <el-container class="main" v-show="!state.pageShow">
        <el-aside :style="{ minHeight: domHeight + 'px'}">
          <div class="u-dropdown-div">
            组件列表
          </div>
          <div v-if="state.leftMenuShow">
            <div>
              <el-scrollbar :style="{ height: domHeight - 100 + 'px'}">
                <el-collapse
                  ref="trans"
                  v-show="state.pluginMenu.show"
                  collapse-transition="true">
                  <!-- 转换组件 -->
                  <el-collapse-item class=""
                                    v-for="(item, index) in state.pluginMenu.transData"
                                    :key="index"
                                    :name="index"
                                    :title="item.name">
                    <div class="u-plugin-div"
                        v-for="(plugin, index) in item.children"
                        :key="index"
                        :id="plugin.pluginId"
                        :ref="el => setDragMapRef(el, `trans-${plugin.pluginId}`)"
                      >
                      <el-tooltip effect="light" placement="right">
                        <template #content>
                          <div style="width: 200px;font-size: 14px;">
                            <div style="font-weight: bold; margin-bottom: 5px;">{{plugin.name}}:</div>
                            {{plugin.description}}
                          </div>
                        </template>
                        <div style="outline:none; display: flex; align-items: center; ">
                          <img :src="`${global.IMAGE_PATH}${plugin.image}`" style="width: 32px;"/>
                          <span>{{plugin.name}}</span>
                        </div>
                      </el-tooltip>
                    </div>
                  </el-collapse-item>
                </el-collapse>
                <el-collapse
                  ref="job"
                  v-show="!state.pluginMenu.show">
                  <!-- 作业组件 -->
                  <el-collapse-item class=""
                                    v-for="(item, index) in state.pluginMenu.jobData"
                                    :key="index"
                                    :name="index"
                                    :title="item.name">
                    <div class="u-plugin-div"
                        v-for="(plugin, index) in item.children"
                        :key="index"
                        :id="plugin.pluginId"
                        :ref="el => setDragMapRef(el, `job-${plugin.pluginId}`)"
                      >
                      <img :src="`${global.IMAGE_PATH}${plugin.image}`"/>
                      <span>{{plugin.name}}</span>
                    </div>
                  </el-collapse-item>
                </el-collapse>
              </el-scrollbar>
            </div>
          </div>
        </el-aside>
        <!-- tab页 -->
        <el-main :style="{ height: domHeight + 'px'}"
                v-loading.lock="state.tab.loading"
                element-loading-text="加载中，请耐心等待">
          <el-tabs
            v-model="state.tab.activeName"
            type="card"
            v-if="visible"
          >
            <el-tab-pane
              v-for="(item, index) in state.tab.data"
              :key="item.name"
              :label="item.label"
              :name="item.name"
              :type="item.type"
              :closable="false">
              <span slot="label" v-if="item.type === `${global.TRANS_MODEL}`">
                <img :src="`${global.TRANS_IMAGE_PATH}`"></img> {{item.label}}
              </span>
              <span slot="label" v-else-if="item.type === `${global.JOB_MODEL}`">
                <img :src="`${global.JOB_IMAGE_PATH}`"></img> {{item.label}}
              </span>
              <!-- <keep-alive> -->
                <component
                  :ref="el => getTabRef(el, index)"
                  v-bind:is="item.content">
                </component>
              <!-- </keep-alive> -->
            </el-tab-pane>
          </el-tabs>
          <div style="position: fixed; right: 70px; top: 60px;" >
            <el-tooltip content="高级任务配置" placement="bottom" effect="light">
              <el-button @click="openSettings" circle type="primary"
                        icon="el-icon-setting">
              </el-button>
            </el-tooltip>
          </div>
          <div style="position: fixed; right: 20px; top: 60px;" >
            <el-tooltip content="保存" placement="bottom" effect="light">
              <el-button @click="saveClick" circle type="primary"
                        icon="el-icon-upload" :disabled="state.saveButton.disabled">
              </el-button>
            </el-tooltip>
          </div>
        </el-main>
      </el-container>
      <!-- 资源库弹窗 -->
      <div>
        <el-dialog
          append-to-body
          title="资源库" v-el-drag-dialog
          v-model="state.repository_.dialogVisible"
          :close-on-click-modal="false"
          v-if="state.repository_.show">
          <u-repository ref="repository" @openRepository="openRepository_"></u-repository>
        </el-dialog>
      </div>
      <!-- 组件弹窗 -->
      <div>
        <el-dialog
          append-to-body
          :title="state.plugin.dialogTitle"
          v-model="state.plugin.dialogVisible"
          :width="state.plugin.width" v-el-drag-dialog
          v-if="state.plugin.show"
          :close-on-click-modal="false"
          @close="state.plugin.show = false"
          class="u-el-dialog">
          <transition>
            <keep-alive>
              <component
                ref="pluginComponentRef"
                v-bind:is="state.plugin.component"
                @hook:mounted="setChildData"
                @savePluginData="savePluginData"
                @saveTempPluginData="saveTempPluginData"
                @cancel="state.plugin.dialogVisible=false">
              </component>
            </keep-alive>
          </transition>
        </el-dialog>
      </div>
      <!-- 保存流程时的弹框 -->
      <div>
        <el-dialog
          append-to-body
          :title="state.flow.dialogTitle"
          v-model="state.flow.dialogVisible"
          :close-on-click-modal="false"
          width="30%">
          <save-flow ref="flowRef"></save-flow>
          <span slot="footer" class="dialog-footer">
              <el-button
                icon="el-icon-back"
                @click="state.flow.dialogVisible = false">取消
              </el-button>
            <el-button type="primary" @click="saveSubmit" icon="el-icon-check" :disabled="state.saveSubmitButton">保存</el-button>
          </span>
        </el-dialog>
      </div>
      <div>
        <el-dialog
            append-to-body
            :title="state.flink.dialogTitle"
            v-model="state.flink.dialogVisible"
            :close-on-click-modal="false"
            width="50%">
          <el-form ref="form" :model="state.flinkJobParam" label-width="140px">
            <el-form-item label="执行模式:">
              <el-select v-model="state.flinkJobParam.type" placeholder="请选择执行模式">
                <el-option label="Local" value="Local"></el-option>
                <el-option label="Standalone" value="Standalone"></el-option>
                <el-option label="Yarn Session" value="Yarn Session"></el-option>
                <el-option label="Yarn Per-Job" value="Yarn Per-Job"></el-option>
                <el-option label="Yarn Application" value="Yarn Application"></el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="Flink集群:" v-if="state.flinkJobParam.type === 'Standalone'||state.flinkJobParam.type === 'Yarn Session'">
              <el-select v-model="state.flinkJobParam.clusterId" placeholder="请选择Flink集群">
                <el-option
                    v-for="item in state.taskData.clusterInStanceData"
                    :key="item.id"
                    :label="item.name"
                    :value="item.id"
                />
              </el-select>
            </el-form-item>
            <el-form-item label="Flink集群:" v-if="state.flinkJobParam.type === 'Yarn Per-Job'||state.flinkJobParam.type === 'Yarn Application'">
              <el-select v-model="state.flinkJobParam.clusterConfigurationId" placeholder="请选择Flink集群">
                <el-option
                    v-for="item in state.taskData.clusterConfigurationData"
                    :key="item.id"
                    :label="item.name"
                    :value="item.id"
                />
              </el-select>
            </el-form-item>
            <el-form-item label="SavePoint策略:">
              <el-select v-model="state.flinkJobParam.savePointStrategy" :disabled="state.defaultTaskData && state.defaultTaskData.step >= 4" placeholder="请选择SavePoint策略">
                <el-option
                    v-for="item in state.savePointStrategyOptions"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                />
              </el-select>
            </el-form-item>
            <el-form-item label="任务并行度:">
            <el-input-number v-model="state.flinkJobParam.parallelism"  :min="1" :max="10" label="描述文字"></el-input-number>
            </el-form-item>
            <el-form-item label="CheckPoint:">
              <el-input-number v-model="state.flinkJobParam.checkPoint"  :min="1" :max="10" label="描述文字"></el-input-number>
            </el-form-item>
            <el-form-item label="Insert语句集:">
              <el-switch
                  v-model="state.flinkJobParam.statementSet"
                  active-color="#13ce66"
                  inactive-color="#ff4949">
              </el-switch>
            </el-form-item>
            <el-form-item label="是否全局变量:">
              <el-switch
                  v-model="state.flinkJobParam.fragment"
                  active-color="#13ce66"
                  inactive-color="#ff4949">
              </el-switch>
            </el-form-item>
            <el-form-item label="批模式:">
              <el-switch
                  v-model="state.flinkJobParam.batchModel"
                  active-color="#13ce66"
                  inactive-color="#ff4949">
              </el-switch>
            </el-form-item>
            <el-form-item label="是否报警:">
              <el-switch
                  v-model="state.flinkJobParam.alertGroupId"
                  active-color="#13ce66"
                  :active-value="1"
                  :inactive-value="0"
                  inactive-color="#ff4949">
              </el-switch>
            </el-form-item>
            <el-form-item style="margin-left: 500px">
              <el-button type="primary" @click="submitForm('ruleForm')">保存</el-button>
              <el-button @click="resetForm('ruleForm')">关闭</el-button>
            </el-form-item>
          </el-form>
        </el-dialog>
      </div>
      <!-- ======================画布右键弹框================== -->
      <!-- 右键查看图形文件 引擎文件弹框 -->
      <div>
        <el-dialog
          append-to-body
          :title="state.preview.dialogTitle"
          v-model="state.preview.dialogVisible"
          :close-on-click-modal="false">
          <el-input
            class="u-textarea"
            type="textarea"
            readonly
            resize = "none"
            v-model="state.preview.xml"
            :rows="15"
          />
        </el-dialog>
      </div>
      <!-- ======================组件右键弹框================== -->
      <!-- 查看输入输出字段 -->
      <div>
        <el-dialog
          append-to-body
          :title="state.fields.dialogTitle"
          v-model="state.fields.dialogVisible"
          :close-on-click-modal="false">
          <show-fields ref="showFieldsRef"></show-fields>
          <span slot="footer" class="dialog-footer">
            <el-button type="primary" @click="state.fields.dialogVisible=false">确定</el-button>
          </span>
        </el-dialog>
      </div>
      <!-- 异常处理 -->


  <!--    <div>-->
  <!--      <el-dialog-->
  <!--        v-model="error.dialogVisible"-->
  <!--        :width="plugin.width" v-el-drag-dialog-->
  <!--        v-if="error.dialogVisible"-->
  <!--        @close="error.dialogVisible = false"-->
  <!--        title="步骤错误处理"-->
  <!--        :close-on-click-modal="false">-->
  <!--        <step-exception ref="stepExceptionRef"-->
  <!--                        @cancel="error.dialogVisible=false"-->
  <!--                        @savePluginData="savePluginData"></step-exception>-->
  <!--      </el-dialog>-->
  <!--    </div>-->

      <!-- 新建注释弹框 -->
      <div>
        <el-dialog
          append-to-body
          :title="state.notepad.dialogTitle"
          v-model="state.notepad.dialogVisible"
          :close-on-click-modal="false"
          width="40%">
          <el-input
            ref="notepadRef"
            type="textarea"
            v-model="state.notepad.value"
            :rows="5"
          />
          <span slot="footer" class="dialog-footer">
            <el-button type="primary" @click="createNotepadHandler">确定</el-button>
            <el-button @click="state.notepad.dialogVisible=false">取消</el-button>
          </span>
        </el-dialog>
      </div>
      <!-- 组件描述信息 -->
      <div>
        <el-dialog
          append-to-body
          :title="state.discription.dialogTitle"
          v-model="state.discription.dialogVisible"
          :close-on-click-modal="false"
          width="40%">
          <el-input
            ref="notepad"
            type="textarea"
            v-model="state.discription.value"
            :rows="5"
          />
          <span slot="footer" class="dialog-footer">
            <el-button type="primary" @click="editDiscriptionHandler">确定</el-button>
            <el-button @click="state.discription.dialogVisible=false">取消</el-button>
          </span>
        </el-dialog>
      </div>
      <!-- 关闭tab页时的提示信息框 -->
      <div>
        <el-dialog
          append-to-body
          class="u-message-dialog"
          title="提示"
          width="25%"
          v-model="state.messageDialog.visible">
          <div class="el-message-box__content">
            <div class="el-message-box__status el-icon-warning"></div>
            <div class="el-message-box__message">
              <p>文件已发生变化，是否保存?</p>
            </div>
          </div>
          <div class="el-message-box__btns">
            <el-button
              class="el-button el-button--default el-button--small"
              type="button"
              @click="state.messageDialog.visible=false">取消</el-button>
            <el-button
              class="el-button el-button--default el-button--small el-button--danger"
              type="button"
              @click="closeTabSaveCancel(state.tab.targetName)">否</el-button>
            <el-button
              class="el-button el-button--default el-button--small el-button--primary"
              type="button"
              @click="closeTabSaveConfirm(state.tab.targetName)">是</el-button>
          </div>
        </el-dialog>
      </div>
      <div>
        <el-dialog
          append-to-body
          width="60%"
          :title="state.database.dialogTitle"
          v-model="state.database.dialogVisible"
          :close-on-click-modal="false">
          <u-database v-if="state.database.dialogVisible" ref='database' @closeDialog="closeDialog"></u-database>
        </el-dialog>
      </div>
    </div>
  </el-dialog>
</template>
<script lang="ts" setup>
import mxgraph from '../graph/VueMxGraphLoader'
import * as mxInit from '../graph/graph'
// 接口api
import API from '../api/index'
// 全局常量
import * as global from '../graph/common/common.js'
// 右键事件方法
import * as popupMenuHandler from '../graph/handler/popup-menu-handler.js'
// 公共方法
import * as studio from '../graph/handler/studio-handler.js'

// 打开资源库
import repository from '../graph/repository/repository.vue'
// 保存流程
import saveFlow from '../graph/repository/save-flow.vue'
// 右键组件查看输入输出字段
import showfields from '../graph/show-fields/show-fields.vue'
import databseDialog from '../graph/database/database-dialog.vue'
import respList from './list.vue'
import xmlToFlinkJSON from '../utils/xmlToFlinkJson.js'
import StepJson from '../data/steps.json'
// import elDragDialog from '../graph/directive/index'
import drag from '../graph/directive/drag'
import * as flinkStudio from "../graph/handler/studio-handler";
import jsonToFlinkXml from '../utils/jsonToFlinkXml.js';
import { queryTaskParams } from "../api/workDevelopment";
import { nextTick, reactive, ref, toRefs, onActivated, defineEmits, onMounted, provide, computed, Directive, defineAsyncComponent, getCurrentInstance, toRef } from "vue";
import { message, Modal } from 'ant-design-vue';
import http from '../utils/studioRequest'
import emitter from '../utils/eventBus';

const transTab = defineAsyncComponent(() => import("../graph/tab/trans-tab.vue"));
const jobTab = defineAsyncComponent(() => import("../graph/tab/trans-tab.vue"));

// let plugins = null;
const {
  mxEvent,
  mxCell,
  mxGeometry,
  mxUtils,
  mxDragSource,
  mxPoint,
  mxImage,
  mxFastOrganicLayout,
  mxCodec,
  mxCellOverlay
} = mxgraph

const domHeight = computed(()=> {
  return document.documentElement['clientHeight'] - 130
})

const vElDragDialog = drag;
//   directives: {
//     elDragDialog,
//     focus: {
//       inserted: function (el) {
//         el.querySelector('#directoryNameInput').focus()
//       },
//       update: function (el) {
//         el.querySelector('#directoryNameInput').focus()
//       }
//     }
//   },

const visible = ref();
const state = reactive({
  graph: undefined,
  query:{},
  visible: false,
  lTaskID: '',
  jobName: '',
  taskScheduleType: '',
  flinkJobParam:{
    type: '',
    clusterConfigurationId: null,
    parallelism: 0,
    checkPoint: 0,
    statementSet: false,
    fragment: false,
    batchModel: false,
    alertGroupId: 0,
    dialect: 'FlinkComponent',
    name: '',
    savePointStrategy: 0,
    savePointPath: '',
    config: [],
    clusterId: null,
    maxRowNum: 100,
    useResult: true,
    useChangeLog: false,
    useAutoCancel: false
  },
  imgUrl: 'src/tdf/assets/images/',
  create: { // 入口部分创建弹框
    dialogVisible: false
  },
  pageShow: true, // 入口模块，操作模块的显示
  leftMenuShow: true, // 左侧组件菜单及标题显示控制
  saveButton: {
    disabled: true, // 控制保存和另存为按钮的点击
    flag: 'save' // save(保存) saveas(另存为) close(关闭tab页)
  },
  // 组件
  plugin: {
    width: '70%',
    component: null, // 插件组件
    dialogVisible: false,
    dialogTitle: '',
    show: false,
    transData: [],
    jobData: []
  },
  pluginMenu: { // 左侧菜单
    show: false,
    transData: [],
    jobData: []
  },
  // tab页
  tab: {
    data: [],
    targetName: '', // 记录当前要删除的tab页名称
    activeName: '', // 当前激活的tab页名称
    active: null, // 当前激活的tab页
    refObj: null, // 保存tab页组件对象
    // closable: true, // 标签页是否可关闭
    nameMap: new Map(), // 记录tab页名称，防止重复
    loading: false
  },
  // 预览xml
  preview: {
    dialogTitle: '',
    dialogVisible: false,
    xml: ''
  },
  // 查看输入输出字段
  fields: {
    dialogTitle: '',
    dialogVisible: false
  },
  error: {
    dialogVisible: false
  },
  // 新建注释
  notepad: {
    dialogTitle: '',
    dialogVisible: false,
    value: ''
  },
  // 鼠标当前位置
  mouse: {
    pageX: 0,
    pageY: 0
  },
  // 资源库
  repository_: {
    dialogVisible: false,
    show: false
  },
  // 流程
  flow: {
    dialogTitle: '',
    dialogVisible: false
  },
  flink: {
    dialogTitle: '',
    dialogVisible: false
  },
  // 组件描述
  discription: {
    dialogTitle: '',
    dialogVisible: false,
    value: ''
  },
  // 模仿$message弹框
  messageDialog: {
    visible: false
  },
  database: {
    dialogTitle: '数据源创建',
    dialogVisible: false
  },
  global: global, // 全局常量
  currentModel: '', // 保存当前模式 作业/转换
  currentCell: null, // 保存当前选中组件
  graphList: [], // 保存graph
  pageHeight: '', // 页面高度，根据父容器高度指定
  saveSubmitButton: false,
  customRuleList: [], // 自定义规则
  //从frombox过来
  timer: null,
  taskData: {
    listSessionEnableData: [],
    clusterConfigurationData: [],
    clusterInStanceData:[]
  },
  defaultTaskData: {},
  filterModel: {
    name: '',
    type: 'standalone',
    clusterConfigurationId: null,
    parallelism: 1,
    savePointStrategy: 0,
    savePointPath: '',

    config: [],
    clusterId: null,
    // checkPoint: 0,
    maxRowNum: 100,
    useResult: true,
    useChangeLog: false,
    useAutoCancel: false
  },
  typeOptions: [ // 该版本暂时只需要standalone模式
    {
      value: 'local',
      name: 'Local'
    },
    {
      value: 'standalone',
      label: 'Standalone'
    },
    {
      value: 'yarn-session',
      name: 'Yarn Session'
    },
    {
      value: 'yarn-per-job',
      name: 'Yarn Per-Job'
    },
    {
      value: 'yarn-application',
      name: 'Yarn Application'
    }
  ],
  savePointStrategyOptions: [
    {
      value: 0,
      label: '禁用'
    },
    {
      value: 1,
      label: '最近一次'
    },
    {
      value: 2,
      label: '最早一次'
    },
    {
      value: 3,
      label: '指定一次'
    }
  ],
  alertGroupDataOptions: [],
  createConfig: {
    key: '',
    value: ''
  }
});



const respListRef = ref();
const init = (query:any) => {
  state.query = query;
  state.tab.data = [];
  visible.value = true;

  nextTick(() => {
    getPageHeight()
    respListRef.value.init('/', createTransHandler, createJobHandler, studio);
    const param = query
    // 判断是否包含token参数
    if (param && param.id) {
      //
      state.lTaskID = param.id
      state.jobName = param.jobName
      if (state.lTaskID) {
        flinkOpen(state.lTaskID, state.jobName)
        queryTaskParamsFunc()
        return
      }
    } else {
      createTransHandler()
    }
  })
  // 跳转进入
  if (query.tableId) {
    loadQcGraph(query.tableId)
  }
};
// =============================打开资源===================================
// 打开资源
const openHandler = () => {
  state.repository_.show = true
  state.repository_.dialogVisible = true
};
const openSettings = () => {
  state.flink.dialogVisible = true;
};
// 打开一个资源
const openRepository_ = async (xml:any, type:any, path:any) => {
  state.currentModel = type
  let flag = false
  // 获取所有tab页数据
  const tabList = state.tab.data
  // 查找当前资源是否已打开
  for (let i = 0; i < tabList.length; i++) {
    const tab = tabList[i]
    if (tab.label === path) { // 当前资源已打开
      state.tab.active = tab
      state.tab.activeName = tab.name
      state.tab.targetName = tab.name
      flag = true
    }
  }
  // 当前资源未打开
  if (!flag) {
    // 初始化
    await createInit(path)
    await nextTick(() => {
      // 加载xml
      loadTextXml(xml)
      // 记录画布上的组件 防止组件重复
      recordPlugin()
      // 在解析后的流程上根据属性补充连线上的图片
      drawingByProperties()
    })
  }
  state.repository_.dialogVisible = false
};
// 加载xml文件
const loadXml = (xml:any) => {
  const layout = new mxFastOrganicLayout(state.graph, 2)
  state.graph.getModel().beginUpdate()
  try {
    var doc = mxUtils.load('/static/studio/job.xml')
    var root = doc.getDocumentElement()
    var dec = new mxCodec(root.owerDocument)
    dec.decode(root, state.graph.getModel())
    var parent = state.graph.getDefaultParent()
    layout.execute(parent)
  } finally {
    state.graph.getModel().endUpdate()
  }
};
// 加载String xml
const loadTextXml = (xml:any) => {
  const layout = new mxFastOrganicLayout(state.graph, 2)
  let parent = null
  state.graph.getModel().beginUpdate()
  try {
    var doc = mxUtils.parseXml(xml)
    var root = doc.documentElement
    var dec = new mxCodec(root.owerDocument)
    dec.decode(root, state.graph.getModel())
    parent = state.graph.getDefaultParent()
    layout.execute(parent)
  } finally {
    state.graph.getModel().endUpdate()
  }
};
// 记录画布上的组件 防止组件重复
const recordPlugin = () => {
  // 获取画布上的所有组件
  const parent = state.graph.getDefaultParent()
  const cells = parent.children
  if (cells !== null && cells.length > 0) {
    for (let i = 0; i < cells.length; i++) {
      const cell = cells[i]
      const cellName = cell.getAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_NAME)
      state.tab.refObj.state.pluginNameMap.set(cellName, cellName)
    }
  }
};
// 在解析后的流程上根据属性补充连线上的图片
const drawingByProperties = () => {
  // 获取画布上的所有组件
  const parent = state.graph.getDefaultParent()
  const cells = parent.children
  if (cells !== null && cells.length > 0) {
    if (state.currentModel === global.TRANS_MODEL) {
      transDrawingByProperties(cells)
    } else {
      jobDrawingByProperties(cells)
    }
  }
};

// 在解析后的转换流程上根据属性补充连线上的图片
const transDrawingByProperties = async (cells:any) => {
  // 根据数据发送属性画图
  await drawingBydataDeliverProperties(cells)
};

// 根据数据发送属性在连线上画图
const drawingBydataDeliverProperties = async (cells:any) => {
  let overlay = new mxCellOverlay(new mxImage(global.EDGE_ELEMENT_IMAGE_PATH, 16, 16), '')
  // 鼠标样式
  overlay.cursor = 'move'
  for (let i = 0; i < cells.length; i++) {
    const cell = cells[i]
    if (!cell.edge) {
      const distributValue = cell.getAttribute('distribute')
      if (distributValue === 'N') {
        const childrenCells = cell.children
        if (childrenCells.length > 0) {
          for (let i = 0; i < childrenCells.length; i++) {
            const childrenCell = childrenCells[i]
            if (childrenCell.edges) {
              const edges = childrenCell.edges
              for (let j = 0; j < edges.length; j++) {
                const edge = edges[j]
                const enabled = edge.getAttribute('enabled')
                if (enabled === 'Y') {
                  edge.style = 'hop'
                } else {
                  edge.style = 'hop;disabled'
                }
                // graph.setCellStyles(mxConstants.STYLE_STROKECOLOR, global.EDGE_ELEMENT_STYLE_DEFAULT_STROKECOLOR);
                let overlays = state.graph.getCellOverlays(edge)
                overlays = overlay
                state.graph.addCellOverlay(edge, overlays)
                state.graph.refresh(edge)
              }
            }
          }
        }
      }
    }
  }
};

// 在解析后的作业流程上根据属性补充连线上的图片
const jobDrawingByProperties = (cells:any) => {
  // 根据评价条件画图
  drawingByRateCondition(cells)
};
// 在解析后的作业流程上根据评价条件在连线上画图
const drawingByRateCondition = (cells:any) => {
  for (let i = 0; i < cells.length; i++) {
    const cell = cells[i]
    let image = null
    if (cell.edge) {
      const evaluation = cell.getAttribute('evaluation')
      const unconditional = cell.getAttribute('unconditional')
      let parallel = cell.source.parent.getAttribute('parallel')
      const enableValue = cell.getAttribute(global.EDGE_ELEMENT_ATTRIBUTE_ENABLED)
      studio.setEdge(state.graph, global.JOB_MODEL, cell, enableValue, parallel)
      if (unconditional === global.EDGE_ELEMENT_ATTRIBUTE_UNCONDITION_TRUE_VALUE) {
        image = global.PLUGIN_STATE_IMAGE_UNCONDITION
      } else {
        if (evaluation === global.EDGE_ELEMENT_ATTRIBUTE_EVALUATION_TRUE_VALUE) {
          image = global.PLUGIN_STATE_IMAGE_TRUE
        } else {
          image = global.PLUGIN_STATE_IMAGE_FALSE
        }
      }
      let overlays = state.graph.getCellOverlays(cell)
      overlays = new mxCellOverlay(new mxImage(image, 16, 16), '')
      // 鼠标样式
      overlays.cursor = 'move'
      state.graph.addCellOverlay(cell, overlays)
      if (parallel === 'Y') {
        let overlays = state.graph.getCellOverlays(cell)
        overlays = new mxCellOverlay(
          new mxImage(global.EDGE_ELEMENT_PARALLEL_HOP, 16, 16), '', null, null, new mxPoint(20, 0), 'move')
        state.graph.addCellOverlay(cell, overlays)
      }
    }
  }
};
// =============================创建相关操作===================================
// 点击创建作业或转换按钮
const createHandler = () => {
  state.create.dialogVisible = true
};
// 创建作业
const createJobHandler = async () => {
  /// 保存当前模式
  state.currentModel = global.JOB_MODEL
  // 初始化mxGraph
  await createInit()
  // 关闭弹框
  state.create.dialogVisible = false
};
// 创建转换
const createTransHandler = async () => {
  // 保存当前模式
  state.currentModel = global.TRANS_MODEL
  // 创建初始化
  await createInit()
  state.create.dialogVisible = false
};
// 创建初始化
const createInit = async (tabName:any) => {
  state.currentCell = null
  let plugins = null
  // 加载插件数据
  if (state.currentModel === global.TRANS_MODEL) {
    // console.log(StepJson)
    // 加载转换数据
    plugins = StepJson // await API.studio.listStep()
  } else {
    // 加载作业数据
    plugins = await API.studio.listEntry()
  }
  // 创建标签
  await createTab(tabName)
  // 显示左侧菜单及标题部分
  state.leftMenuShow = true
  // 控制保存 另存为按钮可点击
  state.saveButton.disabled = false
  // 初始化mxGraph
  setTimeout(async () => {
    await graphInit(plugins)
    // 显示控制
    displayHandler(state.currentModel)
    // 关闭弹框
    state.create.dialogVisible = false
  }, 1000);

};
// 初始化mxGraph
const graphInit = async (pluginData:any) => {
  await nextTick(async () => {
    // 1.获取创建tab页中的画布容器
    let containerRef = state.tab.refObj.graphContainerRef;
    let outline = state.tab.refObj.outlineRef;
    if (containerRef && pluginData) {
      // if(pluginData){
      // 2.调用初始化方法
      mxInit.init('', state.currentModel, containerRef, pluginData, outline)
      let graph = mxInit.getGraph()
      debugger
      state.graph = {...toRefs(graph)};
      // 3.保存graph对象
      state.graphList.push(state.graph)
      // 4.加载组件菜单
      if (state.graph) {
        // 将graph,this传到tab页,右键事件js中
        deliverVariable(state.tab.refObj)
        deliverVariable(popupMenuHandler)
        if (state.currentModel === global.TRANS_MODEL) {
          // 加载转换插件
          await loadTransPlugins(pluginData)
        } else {
          // 加载作业插件
          await loadJobPlugins(pluginData)
        }
        // setTimeout(function () {
          let ruleList = []
          let targetColumn = []
          const name = state.graph.getDefaultParent().getAttribute('name')
          if (!name) {
            return
          }
          http({
            url: http.adornUrl(`/di/sql/design/info/${name}`),
            method: 'get',
            params: http.adornParams()
          }).then(({data:any}) => {
            if (data && data.code === 0) {
              ruleList = data.ruleList
              targetColumn = data.targetColumn
              if (ruleList.length > 0 || targetColumn.length > 0) {
                for (let cell of state.graph.getDefaultParent().children) {
                  const type = cell.getAttribute('type')
                  if (type === 'TableInput') {
                    let tempNodeStr = cell.value.innerHTML
                    let textNode = new DOMParser().parseFromString(tempNodeStr, 'text/html').body.childNodes[0]
                    let currentData = textNode.getAttribute(global.SAVE_FORMDATA_ELEMENT_ATTRIBUTE)
                    const jsonObj = JSON.parse(currentData)
                    let cellRuleList = []
                    for (let item of ruleList) {
                      if (item.cellId === cell.id) {
                        cellRuleList.push(item)
                      }
                    }
                    let cellTargetColumn = []
                    for (let item of targetColumn) {
                      if (item.cellId === cell.id) {
                        cellTargetColumn.push(item)
                      }
                    }
                    jsonObj.sqlForm = {
                      src: jsonObj.connection.id,
                      alias: 0,
                      ruleList: cellRuleList,
                      targetColumn: cellTargetColumn
                    }
                    textNode.setAttribute(global.SAVE_FORMDATA_ELEMENT_ATTRIBUTE, JSON.stringify(jsonObj))
                    cell.value.innerHTML = textNode.outerHTML
                  }
                }
              }
            } else {
              message.error(data.msg)
            }
          })
        // }, 500)
      }
    }
  })
};
// 加载作业插件
const loadJobPlugins = async (pluginData:any) => {
  if (state.pluginMenu.jobData.length === 0) {
    state.pluginMenu.jobData = pluginData
    addDraggableSource(state.pluginMenu.jobData)
  }
};
// 加载转换插件
const loadTransPlugins = async (pluginData:any) => {
  if (state.pluginMenu.transData.length === 0) {
    state.pluginMenu.transData = pluginData
    addDraggableSource(state.pluginMenu.transData)
  }
};
// 组件数据添加图片属性
const pluginsImageshandler = (pluginsGroup:any, images:any) => {
  for (let i = 0; i < pluginsGroup.length; i++) {
    const pluginChildren = pluginsGroup[i].children
    for (let j = 0; j < pluginChildren.length; j++) {
      const plugin = pluginChildren[j]
      for (let z = 0; z < images.length; z++) {
        if (plugin.pluginId === images[z].pluginId) {
          plugin.image = images[z].image
        }
      }
    }
  }
  return pluginsGroup
};
//表单
const submitForm = () => {
  state.flink.dialogVisible = false;
};
const resetForm = () => {
  state.flink.dialogVisible = false;
};
/***
 * 翻译中文提醒
 * @plugin 转换组件
 */
const tranDesc = (plugin:any) => {
  switch (plugin.pluginId) {
    // case 'elasticsearch-bulk':
    case 'UrlValidator':
      plugin.name = 'URL校验'
      plugin.description = ''
      plugin.image = 'validator.png'
      break
    case 'csv-input':
      plugin.name = '正则检验'
      plugin.description = ''
      plugin.image = 'validator.png'
      break
    case 'sm3':
      plugin.name = '加密（普通)'
      plugin.description = ''
      break
    case 'sm4':
      plugin.name = '加密（国密SM-4)'
      plugin.description = ''
      break
    case 'range-validator':
      plugin.name = '数值范围判断'
      // plugin.name = 'HDFS 文件输入'
      plugin.description = ''
      plugin.image = 'validator.png'
      break
    case 'hadoop-file-output':
      // plugin.name = 'HDFS 文件输出'
      plugin.name = '空值判断'
      plugin.description = ''
      plugin.image = 'validator.png'
      break
    case 'mongodb-input':
      plugin.name = 'kafka输入'
      plugin.description = ''
      break
    case 'mongodb-output':
      plugin.name = 'kafka输出'
      plugin.description = ''
      break
  }
  state.imgUrl = 'src/tdf/assets/images/'+ plugin.image
};
// 添加可拖拽元素
const dragMapRef = ref({});
const setDragMapRef = (el:HTMLElement, keyName:String) => {
  if(el) {
    console.log('set dragMapRef', el, keyName)
    dragMapRef.value[keyName] = el;
  }
}
const addDraggableSource = (plugins:any) => {
  // 查找当前使用的graph对象
  var graphF = function (evt:any) {
    var x = mxEvent.getClientX(evt)
    var y = mxEvent.getClientY(evt)
    var elt = document.elementFromPoint(x, y)
    for (var i = 0; i < state.graphList.length; i++) {
      if (mxUtils.isAncestorNode(state.graphList[i].container, elt)) {
        return state.graphList[i]
      }
    }
    return null
  }
  // 前缀处理，用于拼接refId
  const prefixResult = prefixHandler()
  // 遍历菜单组件添加为可拖拽元素
  for (let i = 0; i < plugins.length; i++) {
    const group = plugins[i]
    if (plugins[i].name === 'Big Data') {
      plugins[i].name = '大数据'
    }
    for (let j = 0; j < group.children.length; j++) {
      const plugin = group.children[j]
      tranDesc(plugin)

      nextTick(() => {
        // 根据refs获取拖拽对象
        const refId = `${prefixResult.prefix}${plugin.pluginId}`
        console.log('get dragMapRef', dragMapRef, refId)
        let dragElt = dragMapRef.value[refId];
        // 设置div 可拖拽 （解决firefox上只能拖拽图片的问题）
        dragElt.draggable = true
        let cloneNode = dragElt.childNodes[1];
        cloneNode.style.width = '140px'
        // 创建自定义标签
        const element = userDefinedElement(plugin)
        // Function that is executed when the image is dropped on
        // the graph. The cell argument points to the cell under
        // the mousepointer if there is one.
        // 拖拽组件时触发的事件
        var funct = function (graph:any, evt:any, cell:any, x:any, y:any) {
          // var parent = graph.getDefaultParent();
          var model = graph.getModel()
          var v = null
          model.beginUpdate()
          try {
            // 创建组件
            const style = prefixResult.baseStyle + refId
            v = new mxCell(element, new mxGeometry(0, 0, 48, 48), style)
            v.vertex = true
            // start组件只允许有一个
            const cellName = v.getAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_NAME)
            if (cellName === global.JOB_PLUGIN_START) {
              if (state.tab.refObj.state.pluginNameMap.has(cellName)) {
                message.warning('一个任务里只能使用一次开始组件')
                return
              }
            }
            // Adds the ports at various relative locations
            var input = graph.insertVertex(v, null, global.PLUGIN_INPUT_TOOLTIP, 0, 0.5, 16, 16,
              `port;port-input`, true)
            input.geometry.offset = new mxPoint(-8, -8)
            var output = graph.insertVertex(v, null, global.PLUGIN_OUTPUT_TOOLTIP, 1, 0.5, 16, 16,
              `port;port-output`, true)
            output.geometry.offset = new mxPoint(-8, -8)
            // 克隆组件
            var cells = graph.importCells([v], x, y, cell)
            if (cells != null && cells.length > 0) {
              graph.scrollCellToVisible(cells[0])
              graph.setSelectionCells(cells)
            }
            // 拖拽多个相同组件时 组件名称不重复的处理
            repeatPluginHandler(cells[0])
          } finally {
            model.endUpdate()
          }
          // graph.setSelectionCell(v);
        }
        // 添加拖拽元素
        var ds = mxUtils.makeDraggable(dragElt, graphF, funct, cloneNode, 0, 0, true, true)
        ds.setGuidesEnabled(true)
        ds.createDragElement = mxDragSource.prototype.createDragElement
      })
    }
  }
};
// 前缀处理
const prefixHandler = () => {
  // 用于拼接ref
  let prefix = ''
  let baseStyle = null
  if (state.currentModel === global.TRANS_MODEL) {
    prefix = 'trans-'
    baseStyle = 'step;'
  } else {
    prefix = 'job-'
    baseStyle = 'entry;'
  }
  return { 'prefix': prefix, 'baseStyle': baseStyle }
};
// 处理拖拽的重复组件
const repeatPluginHandler = (cell:any) => {
  const cellName = cell.getAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_NAME)
  if (state.tab.refObj.state.pluginNameMap.has(cellName)) {
    let newName = cellName
    while (state.tab.refObj.state.pluginNameMap.has(newName)) {
      const exitNameSuffixNum = state.tab.refObj.state.pluginNameMap.get(newName).replace(/[^0-9]/ig, '')
      let newSuffixNum = 1
      if (exitNameSuffixNum) {
        newSuffixNum = parseInt(exitNameSuffixNum)
      }
      newName = state.tab.refObj.state.pluginNameMap.get(cellName) + (newSuffixNum + 1)
    }
    state.tab.refObj.state.pluginNameMap.set(newName, newName)
    cell.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_NAME, newName)
  } else {
    state.tab.refObj.state.pluginNameMap.set(cellName, cellName)
  }
};
// 创建自定义组件标签
const userDefinedElement = (plugin:any) => {
  var doc = mxUtils.createXmlDocument()
  var element = null
  if (state.currentModel === global.TRANS_MODEL) {
    element = doc.createElement(global.TRANS_ELEMENT)
  } else if (state.currentModel === global.JOB_MODEL) {
    element = doc.createElement(global.JOB_ELEMENT)
  }
  // 默认属性
  element.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_NAME, plugin.name)
  element.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_TYPE, plugin.type)
  element.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_PLUGIN_ID, plugin.pluginId)
  element.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_DESCRIPTION, '')
  element.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_DISTRIBUTE, 'Y')
  element.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_CUSTOM_DISTRIBUTION, '')
  element.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_COPIES, 1)
  element.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_PARTITIONING, '')
  element.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_ATTRIBUTES, '')
  element.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_CLUSTER_SCHEMA, '')
  element.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_REMOTESTEPS, '')
  element.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_DRAW, 'Y')
  element.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_PARALLEL, 'N')

  // start dummy组件上添加start,dummy属性进行区分
  if (plugin.pluginId === 'start') {
    element.setAttribute('start', 'Y')
    element.setAttribute('dummy', 'N')
  } else if (plugin.pluginId === 'dummy') {
    element.setAttribute('start', 'N')
    element.setAttribute('dummy', 'Y')
  }
  return element
};
// 显示控制
const displayHandler = (currentModel:any) => {
  // 显示操作模块隐藏入口模块
  state.pageShow = false
  if (currentModel === global.TRANS_MODEL) {
    // 显示转换组件菜单
    state.pluginMenu.show = true
  } else if (currentModel === global.JOB_MODEL) {
    // 显示作业组件菜单
    state.pluginMenu.show = false
  }
};
// 传递graph,this,gloabal到其他js中
const deliverVariable = (jsHandler:any) => {
  // 向右键事件js中传递 graph,this
  if (jsHandler.setGraph) {
    jsHandler.setGraph(state.graph)
  }
  // if (jsHandler.setThis) {
  //   jsHandler.setThis(this)
  // }
};
// 创建标签页
const createTab = async (tabName:any) => {
  let title = ''
  let content = undefined;
  let type = ''
  if (state.currentModel === global.TRANS_MODEL) {
    title = '转换'
    content = transTab
    type = global.TRANS_MODEL
  } else if (state.currentModel === global.JOB_MODEL) {
    title = '作业'
    content = jobTab
    type = global.JOB_MODEL
  }
  if (tabName) {
    title = tabName
  }
  await createTabHandler(title, content, type)
};

// 执行创建tab页操作
const TabRefs = ref([]);
const getTabRef = (el:any, index:number) => {
  if (el) {
    TabRefs.value.push(el);
    state.tab.refObj = el;
  }
};
const createTabHandler = async (label:any, content:any, type:any) => {
  // 重复tab页名称处理
  let newLabel = await repeatTabNameHandler(label)
  const newTab = {
    label: state.query.jobName,
    name: newLabel,
    type: type,
    content: content,
    closable: true
  }
  state.tab.data.push(newTab)
  state.tab.activeName = newLabel
  state.tab.targetName = newLabel
  state.tab.active = newTab
  state.currentCell = null
  // 保存当前创建的tab页组件对象
  nextTick(() => {
    state.tab.refObj = TabRefs.value[0]
  })
};
// 重复tab页名称处理
const repeatTabNameHandler = (label:any) => {
  let newLabel = label
  let newIndex = 1
  if (state.tab.nameMap.has(newLabel)) {
    while (state.tab.nameMap.has(newLabel)) {
      const oldIndex = state.tab.nameMap.get(newLabel).replace(/[^0-9]/ig, '')
      if (oldIndex) {
        newIndex = parseInt(oldIndex) + 1
      }
      newLabel = state.tab.nameMap.get(label) + newIndex
    }
    state.tab.nameMap.set(newLabel, newLabel)
  } else {
    state.tab.nameMap.set(newLabel, newLabel)
  }
  return newLabel
};

// 修改tab页名称 并重新指定graph
const updateTabName = async (newName:any) => {
  // 从记录tab页名称的map中删除修改之前的tab页名称
  state.tab.nameMap.delete(state.tab.activeName)
  const xml = await studio.getMxGraphXml(state.graph)
  await state.tab.data.forEach((item:any, index:any) => {
    if (item.name === state.tab.activeName) {
      item.name = newName
      item.label = newName
      state.tab.active = item
      state.tab.activeName = newName
      state.tab.targetName = newName
    }
  })
  // 将新的tab页名称添加到map中
  state.tab.nameMap.set(newName, newName)
  state.tab.refObj = this.$refs[newName][0]

  let plugins = null
  // 加载插件数据
  if (state.currentModel === global.TRANS_MODEL) {
    // 加载转换数据
    plugins = StepJson // await API.studio.listStep()
  } else {
    // 加载作业数据
    plugins = await API.studio.listEntry()
  }
  await graphInit(plugins)
  nextTick(() => {
    // 加载xml
    loadTextXml(xml)
    // 记录画布上的组件 防止组件重复
    recordPlugin()
    // 在解析后的流程上根据属性补充连线上的图片
    drawingByProperties()
  })
};

// 关闭tab页提示框点击是时的操作
const closeTabSaveConfirm = (targetName:any) => {
  state.messageDialog.visible = false
  closeTabSaveHandler(targetName)
};
// 关闭tab页提示框点击否时的操作
const closeTabSaveCancel = (targetName:any) => {
  state.messageDialog.visible = false
  removeTabDataHandler(targetName)
};
// 删除tab页数据
const removeTabDataHandler = (targetName:any) => {
  // 获取所有的tab页数据
  let tabs = state.tab.data
  // 当前激活的tab页
  let activeName = state.tab.activeName
  let targetTab = null
  // 当前要删除的tab为激活tab
  if (activeName === targetName) {
    tabs.forEach((tab, index) => {
      if (tab.name === targetName) {
        targetTab = tab
        let nextTab = tabs[index + 1] || tabs[index - 1]
        if (nextTab) {
          activeName = nextTab.name
          state.tab.active = nextTab
          // 控制菜单按钮显示
          displayHandler(nextTab.type)
        }
      }
    })
    // 重新指定激活页
    state.tab.activeName = activeName
    // 保存新激活页组件对象
  } else {  // 当前要删除的tab不是激活tab
    tabs.forEach((tab, index) => {
      if (tab.name === targetName) {
        targetTab = tab
      }
    })
  }
  // 删除tab页数据
  state.tab.data = tabs.filter(tab => tab.name !== targetName)
  // 从记录tab页名称的map中删除该名称
  state.tab.nameMap.delete(targetTab.name)
  // 删除tab页后的一些重置操作
  removeTabReset()
};
// 删除tab页后的一些重置操作
const removeTabReset = () => {
  if (state.tab.data.length === 0) {
    // 转换菜单，组件菜单数据置空
    state.pluginMenu.transData = []
    state.pluginMenu.jobData = []
    // 隐藏左侧菜单及标题
    state.leftMenuShow = false
    // 控制保存和另存为按钮不可点
    state.saveButton.disabled = true
    state.pageShow = true
    nextTick(() => {
      respListRef.value.listRepository()
    })
  }
};

// ==========================================组件操作=====================
// 双击编辑组件
const editPluginByDoubleClick = async (cell:any) => {
  debugger
  state.currentCell = cell
  if (cell.value.nodeName === global.NOTE_ELEMENT) {
    // 注释组件双击
    editNotePluginByDoubleClick(cell)
    return
  }
  const pluginId = global.ELEMENT_DEFAULT_ATTRIBUTE_PLUGIN_ID
  const name = global.ELEMENT_DEFAULT_ATTRIBUTE_NAME
  const componentName = state.currentCell.getAttribute(pluginId)
  if (componentName === 'dummy' || componentName === 'start' || componentName === 'rows-to-result') {
    state.plugin.width = '40%'
  } else {
    state.plugin.width = '70%'
  }
  const title = state.currentCell.getAttribute(name)
  state.plugin.dialogTitle = title
  state.plugin.dialogVisible = true
  state.plugin.show = true
  const directory = state.currentModel === global.TRANS_MODEL ? 'trans' : 'job'
  const path = state.currentModel === global.TRANS_MODEL ? 'steps' : 'entries'

  const modules = import.meta.glob('@/views/workDevelopment/components/studio/**/*.js', { eager: false});
  state.plugin.component = defineAsyncComponent(modules[`/src/views/workDevelopment/components/studio/${directory}/${path}/${componentName}/index.js`]);

  // 数据回显
  dealWithFormData(state.currentCell)
};
// 双击编辑注释组件
const editNotePluginByDoubleClick = (cell:any) => {
  state.notepad.dialogVisible = true
  state.notepad.dialogTitle = '注释'
  state.notepad.value = cell.getAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_NOTE)
  state.currentCell = cell
};
// 处理组件中的表单数据
const dealWithFormData = (currentCell:any) => {
  let title = currentCell.getAttribute('name')
  if (state.currentCell.value.innerHTML) {
    var tempNodeStr = state.currentCell.value.innerHTML
    let textNode = new DOMParser().parseFromString(tempNodeStr, 'text/html').body.childNodes[0]
    let currentData = textNode.getAttribute(global.SAVE_FORMDATA_ELEMENT_ATTRIBUTE)
    const jsonObj = JSON.parse(currentData)
    jsonObj['name'] = title
    state.currentData = jsonObj
  } else {
    state.currentData = ''
    state.stepName = title
  }
};
/***
 * 保存组件数据
 * @formData
 * @isOpen 是否保持对话框打开
 */
const savePluginData = (formData:any, isOpen:any) => {
  if (!isOpen) {
    state.plugin.dialogVisible = false
  }
  if (formData.is_error === 1) {
    // 异常处理
    state.error.dialogVisible = false
    state.currentCell.setAttribute('error', JSON.stringify(formData))
  } else {
    var doc = mxUtils.createXmlDocument()
    let data = doc.createElement(global.SAVE_FORMDATA_ELEMENT)
    data.setAttribute(global.SAVE_FORMDATA_ELEMENT_ATTRIBUTE, JSON.stringify(formData))
    if (state.currentCell.value.innerHTML) {
      state.currentCell.value.innerHTML = data.outerHTML
    } else {
      state.currentCell.value.appendChild(data)
    }
    state.currentCell.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_NAME, formData.name)
    state.graph.refresh(state.currentCell)

    // 如果更新了组件名称，需要重新更新 错误处理
    const errorData = state.currentCell.getAttribute('error')
    if (errorData) {
      let jsonObj = JSON.parse(errorData)
      if (jsonObj.source_step !== formData.name) {
        jsonObj.source_step = formData.name
        state.currentCell.setAttribute('error', JSON.stringify(jsonObj))
      }
    }
  }
  // 标签当前流程已修改
  state.tab.refObj.updateFlag = true
};
// 临时保存数据
const saveTempPluginData = (formData:any) => {
  var doc = mxUtils.createXmlDocument()
  var data = doc.createElement(global.SAVE_FORMDATA_ELEMENT)
  data.setAttribute(global.SAVE_FORMDATA_ELEMENT_ATTRIBUTE, JSON.stringify(formData))
  if (state.currentCell.value.innerHTML) {
    state.currentCell.value.innerHTML = data.outerHTML
  } else {
    state.currentCell.value.appendChild(data)
  }
};
const pluginComponentRef = ref();
const setChildData = () => {
  if (state.currentData) {
    pluginComponentRef.value.loadData(state.currentData)
    pluginComponentRef.value.setGraph(state.graph)
  } else {
    pluginComponentRef.value.resetFormData(state.stepName)
    pluginComponentRef.value.setGraph(state.graph)
  }
};
// 点击保存
const saveClick = async () => {
  // 保存操作
  await saveHandler()
};
// 保存操作
const saveHandler = async () => {
  // 获取输入表、字段、规则信息
  let inputList = []
  // 获取转换输入输出源id
  let inputId = ''
  let outputId = ''
  if (state.graph.getDefaultParent().children) {
    for (let cell of state.graph.getDefaultParent().children) {
      const type = cell.getAttribute('type')
      if (type === 'TableInput') {
        let tempNodeStr = cell.value.innerHTML
        if (!tempNodeStr) continue
        let textNode = new DOMParser().parseFromString(tempNodeStr, 'text/html').body.childNodes[0]
        let currentData = textNode.getAttribute(global.SAVE_FORMDATA_ELEMENT_ATTRIBUTE)
        const jsonObj = JSON.parse(currentData)
        inputId = jsonObj.connection.id
        // 规则信息
        inputList.push({id: cell.id, ...jsonObj.sqlForm})
      } else if (type === 'TableOutput' || type === 'InsertUpdate') {
        let tempNodeStr = cell.value.innerHTML
        if (!tempNodeStr) continue
        let textNode = new DOMParser().parseFromString(tempNodeStr, 'text/html').body.childNodes[0]
        let currentData = textNode.getAttribute(global.SAVE_FORMDATA_ELEMENT_ATTRIBUTE)
        const jsonObj = JSON.parse(currentData)
        outputId = jsonObj.connection.id
      }
    }
  }
  // 标识当前保存为点击保存按钮保存
  state.saveButton.flag = 'save'
  // const name = graph.getDefaultParent().getAttribute('name')
  const name = state.jobName;
  let result = null
  if (name) {
    try {
      // 修改流程直接保存 没有弹框
      result = await saveFlowXml(state.graph, state.currentModel)
      if (result.status === 200 && result.data.code === 200) {
        // 取消流程已修改标记
        state.tab.refObj.updateFlag = false
        message.success('保存成功');
      } else {
        message.error(result.message);
      }
    } catch (error:any) {
      let msg = ''
      if (error.response) {
        msg = error.response.data.error.message
      } else {
        // msg = error.message
        msg = '请完整配置组件表单及输入输出后再保存'
      }
      console.log(error)
      message.error(msg);
    }
  } else {
    // 打开保存弹框 填写名称 选择路径
    openSaveDialog('保存流程')
  }
};
// 关闭标签页时保存流程
const closeTabSaveHandler = async (targetName:any) => {
  // 标识当前保存流程为关闭tab页时的保存
  state.saveButton.flag = 'close'
  // 关闭提示弹框
  let currentGraph = this.$refs[targetName][0].graph
  const name = currentGraph.getDefaultParent().getAttribute('name')
  let result = null
  let targetTab = null
  if (name) {
    try {
      // 获取当前操作的tab页
      await state.tab.data.forEach((item, index) => {
        if (item.name === targetName) {
          targetTab = item
        }
      })
      // 修改流程后直接保存 没有弹框
      result = await saveFlowXml(currentGraph, targetTab.type)
      if (result.status === 200 && result.data.code === 1) {
        // 删除tab页相关操作
        removeTabDataHandler(targetName)
        message.success('保存成功');
      } else {
        message.error(result.data.error.message);
      }
    } catch (error:any) {

      let msg = ''
      if (error.response) {
        msg = error.response.data.error.message
      } else {
        msg = error.message
      }
      console.log(error)
      message.error(msg);
    }
  } else {
    // 打开保存弹框 填写名称 选择路径
    openSaveDialog()
  }
};
// 打开保存弹框 填写名称 选择路径
const flowRef = ref();
const openSaveDialog = (title:any) => {
  // 第一次保存流程 弹框 填写名称 选择路径
  state.saveSubmitButton = false
  state.flow.dialogVisible = true
  state.flow.dialogTitle = title
  nextTick(() => {
    flowRef.value.reset()
  })
};
// 保存弹框中点击确定操作
const saveSubmit = async () => {
  // 名称，路径保存到标签中
  await flowRef.value.validateForm()
  // 获取当前操作的tab组件的graph
  const currentGraph = this.$refs[state.tab.targetName][0].graph
  let result = null
  let targetTab = null
  if (flowRef.value.flowForm.validateFlag) {
    state.saveSubmitButton = true
    const flowForm = flowRef.value.flowForm;
    currentGraph.getDefaultParent().setAttribute('name', flowForm.name)
    currentGraph.getDefaultParent().setAttribute('directory', flowForm.path)
    try {
      // 获取当前操作的tab页
      await state.tab.data.forEach((item:any, index:any) => {
        if (item.name === state.tab.targetName) {
          targetTab = item
        }
      })
      // 保存流程
      result = await saveFlowXml(currentGraph, targetTab.type)
      // 修复在保存后，未关闭，第二次保存取不到 realdirectory问题
      if (!flowForm.realPath) {
        flowForm.realPath = flowForm.path
      }
      currentGraph.getDefaultParent().setAttribute('realdirectory', flowForm.realPath)

      if (result.status === 200 && result.data.code === 200) {
        message.success('保存成功');
        // 2023年11月21日 flink 临时注释
        // saveToTransForm(flowForm.realPath, flowForm.name)
        state.saveSubmitButton = false
        if (state.saveButton.flag === 'close') { // 当前为关闭tab页操作 保存流程后再进行关闭tab页的相关操作
          await removeTabDataHandler(state.tab.targetName)
        } else if (state.tab.data.length > 0) {
          // 修改当前tab页名称
          updateTabName(flowForm.path + '/' + flowForm.name)
        }
      } else {
        message.error(result.data.error.message);
      }
      // 关闭弹框
      state.flow.dialogVisible = false
    } catch (e:any) {
      console.log(e)
      let msg = ''
      if (e.response) {
        msg = e.response.data.error.message
      } else {
        msg = e.message
      }
      message.error(msg);
    }
  }
};
/***
 * 保存到转换任务表，供作业调用
 */
const saveToTransForm = (path:any, name:any, inputDbId:any, outputDbId:any) => {
  var fileType = 'DB_KTR'
  if (state.currentModel !== global.TRANS_MODEL) {
    fileType = 'DB_KJB'
  }
  if (!path || path === 'undefined') {
    message.error('没取到保存路径，请联系系统管理员');
  }

  http({
    url: http.adornUrl(`/etl/transform/saveResp`),
    method: 'post',
    data: http.adornData({
      transName: name,
      kettleName: name,
      filePath: path + '/' + name,
      fileType: fileType,
      status: 1,
      srcDbId: inputDbId,
      targetDbId: outputDbId
    })
  }).then(({data}) => {
    if (data && data.code === 0) {
      console.log('save trans success')
    }
  })
};
// 保存流程的xml
const saveFlowXml = async (graph:any, type:any) => {
  // const xml = await studio.getMxGraphXml(graph)
  const xmlNode = await studio.getMxGraphNode(graph)
  // console.log(xmlNode)
  let lFlinkSavaParameters = xmlToFlinkJSON.createFlinkSavaParameter(xmlNode)
  // 临时使用测试任务ID=2a1346c22f09b0b2b6238d3fcea90893，jobName = testzy
  // let lTaskID = '430eb7613e26cbac93c14ba6a15b67a9' // getUUID();
  lFlinkSavaParameters.jobName = state.jobName
  lFlinkSavaParameters.taskId = state.lTaskID
  lFlinkSavaParameters.id = state.lTaskID
  lFlinkSavaParameters.flinkJobParam = state.flinkJobParam
  lFlinkSavaParameters.taskScheduleType = state.taskScheduleType
// 2023年11月21日 flink 只需要保存
  return API.trans.flinkSave(lFlinkSavaParameters)
};
// ========================================弹框相关操作=====================
// 创建注释
const createNotepadHandler = () => {
  popupMenuHandler.createNotepadHandler(staet.currentCell)
};
/**
 * 编辑组件描述信息
 */
const editDiscriptionHandler = () => {
  state.currentCell.setAttribute(global.ELEMENT_DEFAULT_ATTRIBUTE_DESCRIPTION, state.discription.value)
  state.graph.refresh(state.currentCell)
  state.discription.dialogVisible = false
};
// =============================其他操作===================================
// 动态设置页面高度
const studioViewRef = ref();
const getPageHeight = () => {
  state.pageHeight = studioViewRef.value.parentElement.clientHeight - 20 + 'px'
};
// 标记当前流程已做修改
const setUpdateFlag = () => {
  state.tab.refObj.updateFlag = true
};
const createDatabaseHandler = () => {
  state.database.dialogVisible = true
  state.create.dialogVisible = false
};
const closeDialog = () => {
  state.database.dialogVisible = false
};

// 打开资源flink
const flinkOpen = async (id:any, jobName:any) => {
  state.loading = true
  // 获取xml
  let result = null
  result = await flinkStudio.flinkGetTransXml(id, jobName)
  state.jobName = result.data.data.jobName;
  if (result.data && result.data.data&& result.data.data.taskScheduleType) {
    state.taskScheduleType = result.data.data.taskScheduleType
  }
  if (result.data && result.data.data && result.data.data.models) {
    let lFlinkJsonModels = result.data.data.models
    let lNewModel = new mxGraphModel()
    let xmlFlinkJsonModel = jsonToFlinkXml.flinkJsonToGraphXml(mxCell, mxGeometry,mxPoint, mxUtils, global, lNewModel, lFlinkJsonModels)
    const enc = new mxCodec(mxUtils.createXmlDocument());
    const node = enc.encode(xmlFlinkJsonModel);
    const xmlFlinkJson = mxUtils.getPrettyXml(node);
    // console.log(xmlFlinkJson)
    // 根据xml加载数据
    openRepository_(xmlFlinkJson, 'transformation', jobName)
    // 关闭加载动画
    state.loading = false
  } else {
    createTransHandler()
  }
};
//从fromBox过来的
const queryTaskParamsFunc = () => {
  queryTaskParams({ taskId: state.lTaskID })
      .then((res:any) => {
        console.log('queryTaskParams=====res====', res)
        state.taskData = res
        state.defaultTaskData = res.defaultTaskData
        state.flinkJobParam.clusterConfigurationId = res.defaultTaskData.clusterConfigurationId
        state.flinkJobParam.name = res.defaultTaskData.name
        state.flinkJobParam.parallelism = res.defaultTaskData.parallelism
        state.flinkJobParam.type = res.defaultTaskData.type
        state.flinkJobParam.savePointStrategy = res.defaultTaskData.savePointStrategy
        state.flinkJobParam.savePointPath = res.defaultTaskData.savePointPath
        if (res.jobJson) {
          state.flinkJobParam.enableDataSyncStartTime = JSON.parse(res.jobJson).enableDataSyncStartTime
          state.flinkJobParam.dataSyncStartTime = JSON.parse(res.jobJson).dataSyncStartTime
        } else {
          state.flinkJobParam.enableDataSyncStartTime = false
          state.flinkJobParam.dataSyncStartTime = ''
        }

        state.flinkJobParam.config = res.defaultTaskData.config.length
            ? res.defaultTaskData.config
            : []
        state.flinkJobParam.clusterId = res.defaultTaskData.clusterId
        if (res.defaultTaskData.jarFileName) {
          state.$emit('getJarName', res.defaultTaskData.jarFileName)
        }
      })
      .finally(() => {
        state.loading = false
      })
};
onActivated (()=> {
  if (state.graph) {
    nextTick(() => {
      // graph.getView().setScale(0.6)
      state.graph.getView().setTranslate(200, 50)
    })
  }
});
const loadQcGraph = async (tableId:any) => {
  // 从数据治理跳转过来，根据表代码、数据源id和数据表id创建图表
  await createTransHandler()
  http({
    url: http.adornUrl(`/src/table/info/${tableId}`),
    method: 'get'
  }).then(({data}) => {
    if (data && data.code === 0) {
      const tableName = data.table.tableName
      const tableCode = data.table.tableCode
      const srcId = data.table.datasourceId
      loadTextXml(`
        <mxGraphModel>
            <root>
                <mxCell id="0"/>
                <info capture_step_performance="N" created_date="" created_user="" description="" directory="/" extended_description="" feedback_shown="Y" feedback_size="50000" id="1" is_key_private="N" key_for_session_key="" modified_date="" modified_user="" name="${tableName}" parameters="[]" realdirectory="/" shared_objects_file="" size_rowset="10000" sleep_time_empty="50" sleep_time_full="50" step_performance_capturing_delay="1000" step_performance_capturing_size_limit="" trans_type="Normal" trans_version="" unique_connections="N" using_thread_priorities="Y">
                    <mxCell parent="0"/>
                </info>
                <step cluster_schema="" copies="1" custom_distribution="" distribute="Y" draw="Y" id="2" name="${tableName}" pluginId="table-input" supports_error_handing="N" type="TableInput">
                    <data value="{&quot;connection&quot;:{&quot;id&quot;:&quot;${srcId}&quot;,&quot;name&quot;:&quot;src&quot;},&quot;sql&quot;:&quot;SELECT *  FROM ${tableCode}  WHERE 1=1 &quot;,&quot;limit&quot;:&quot;0&quot;,&quot;lookup&quot;:null,&quot;execute_each_row&quot;:&quot;N&quot;,&quot;variables_active&quot;:&quot;N&quot;,&quot;lazy_conversion_active&quot;:&quot;N&quot;}"/>
                    <mxCell connectable="0" parent="1" style="trans;step;trans-table-input" vertex="1">
                        <mxGeometry as="geometry" height="40.0" width="40.0" x="280.0" y="110.0"/>
                    </mxCell>
                </step>
                <mxCell id="3" parent="2" style="port;port-input;" value="Input" vertex="1">
                    <mxGeometry as="geometry" height="12.0" relative="1" width="12.0" y="0.5">
                        <mxPoint as="offset" x="-6.0" y="-6.0"/>
                    </mxGeometry>
                </mxCell>
                <mxCell id="4" parent="2" style="port;port-output;" value="Output" vertex="1">
                    <mxGeometry as="geometry" height="12.0" relative="1" width="12.0" x="1.0" y="0.5">
                        <mxPoint as="offset" x="-6.0" y="-6.0"/>
                    </mxGeometry>
                </mxCell>
            </root>
        </mxGraphModel>`)
    } else {
      message.error(data.msg)
    }
  })
}

onMounted(()=> {
  emitter.on('graphMainEvent', graphMainEventHandle);

})

const showFieldsRef = ref();
const stepExceptionRef = ref();
const notepadRef = ref();
interface eventObj {
  type: string;
  data: any;
}
const graphMainEventHandle = (event:eventObj) => {
  const {type, data} = event;
  switch (type) {
    case 'editPluginByDoubleClick':
      editPluginByDoubleClick(data);
      break;
    case 'clearCurrentCell':
      state.currentCell = null;
      break;
    case 'setUpdateFlag':
      setUpdateFlag(data);
      break;
    case 'setMouse':
      state.mouse.pageX = data.pageX;
      state.mouse.pageY = data.pageY;
      break;
    case 'deleteCellName':
      state.tab.refObj.state.pluginNameMap.delete(data);
      break;
    case 'openRepository':
      openRepository_(data.xml, data.type, data.path);
      state.tab.loading = false;
      break;
    case 'editNotePluginByDoubleClick':
      editNotePluginByDoubleClick(data);
      break;
    case 'createNotepad':
      state.notepad.value = '';
      state.notepad.dialogVisible = true;
      state.notepad.dialogTitle = '注释';
      break;
    case 'editPluginDiscription':
      state.discription.dialogTitle = '编辑描述信息';
      state.discription.dialogVisible = true;
      state.discription.value = data.value;
      state.currentCell = data.cell;
      break;
    case 'showInputFields':
      state.fields.dialogVisible = true;
      state.fields.dialogTitle = '步骤里的字段和其来源';
      nextTick(() => {
        showFieldsRef.value.listFields(data.result);
        showFieldsRef.value.showStepName(data.stepName);
      });
      break;
    case 'showOutPutFields':
      state.fields.dialogVisible = true;
      state.fields.dialogTitle = '步骤里的字段和其来源';
      nextTick(() => {
        showFieldsRef.value.listFields(data.result);
        showFieldsRef.value.showStepName(data.stepName);
      });
      break;
    case 'previewKettleXML':
      state.preview.dialogVisible = true;
      state.preview.dialogTitle = '查看引擎文件';
      state.preview.xml = data;
      break;
    case 'previewXML':
      state.preview.dialogVisible = true;
      state.preview.dialogTitle = '查看图形文件';
      state.preview.xml = data;
      break;
    case 'showError':
      state.currentCell = data;
      state.error.dialogVisible = true;
      break;
    case 'stepException':
      nextTick(() => {
        stepExceptionRef.value.setGraph(data.graph);
        stepExceptionRef.value.loadData(data.jsonObj);
      });
      break;
    case 'setLoading':
      state.tab.loading = data;
      break;
    case 'getCurrentModel':
      data(state.currentModel);
      break;
    case 'getNotepadData':
      data(notepadRef.value.state.value, state.notepad.value, state.mouse);
      break;
    case 'closeNotepad':
      state.notepad.dialogVisible = false;
      break;
    default:
      console.log('无此类型');
      break;
  }
}

defineExpose({
  init
});


</script>
<style lang="less" scoped>
  html, body {
    margin: 0;
    padding: 0;
  }
  .studioView {
    overflow: auto;
    width: 100%;
    .u-card-enter {
      width: 400px;
      height: 300px;
      text-align: center;
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
    }
    .u-button-enter {
      width: 70%;
      margin-top: 65px;
      margin-left: 5px;
      left: 50%;
    }
    .u-button-enter2 {
      width: 70%;
      margin-top: 65px;
      margin-left: 15%;
    }
    .main {
      height: 100%;
      .el-header {
        height: 40px !important;
      }
      .el-aside {
        margin-right: 5px;
        border-radius: 5px;
        width: 230px !important;
        padding: 0 5px 5px 5px;
        .u-menu-title {
          height: 40px;
          padding: 0 0 0 15px;;
          line-height: 40px;
        }
        .u-dropdown-div {
          height: 40px;
          padding: 0 5px 0 15px;
          line-height: 40px;
          //border-bottom: 1px solid #ebeef5;
          .el-dropdown {
            margin-right: 10px !important;
          }
          .u-button {
            padding: 5px 8px;
          }
        }
        .el-collapse {
          width: 200px;
          .el-collapse-item__header {
            padding: 0 5px 0 15px;
          }
        }
        .u-plugin-div {
          padding-left: 10px;
        }
        .u-plugin-div:hover {
          background-color:#ecf5ff;
          color:#66b1ff;
          padding-left: 20px;
          cursor: pointer;
        }
      }
      .el-main {
        border-radius: 5px;
        height: 100%;
        padding: 0 3px 3px 3px;
        .el-tabs {
          height: 100%;
          display: -webkit-box; /* Chrome 4+, Safari 3.1, iOS Safari 3.2+ */
          display: -moz-box; /* Firefox 17- */
          display: -webkit-flex; /* Chrome 21+, Safari 6.1+, iOS Safari 7+, Opera 15/16 */
          display: -moz-flex; /* Firefox 18+ */
          display: -ms-flexbox; /* IE 10 */
          display: flex; /* Chrome 29+, Firefox 22+, IE 11+, Opera 12.1/17/18, Android 4.4+ */
          -webkit-box-direction: normal;
          -webkit-box-orient: vertical;
          -moz-flex-direction: column;
          -webkit-flex-direction: column;
          flex-direction: column;
          .el-tabs__header {
            margin: 0;
            height: 40px;
            .el-tabs__nav {
              border-top: none;
              border-left: none;
              border-radius: 0;
            }
          }
          .el-tabs__content {
            flex: 1;
            .el-tab-pane {
              height: 100%;
            }
          }
        }
      }
    }
    // 查看图形文件
    .u-textarea {
      padding-bottom: 10px;
    }
    .u-message-dialog {
      // height: 136px !important;
      padding-bottom: 10px;
      margin-top: 25vh !important;
      .el-dialog__header {
        padding: 10px 20px 0px;
      }
      .el-dialog__body {
        padding: 5px 20px 10px;
      }
    }
  }
  // 右键菜单
  body div.mxPopupMenu {
    background: white;
    position: absolute;
    border: 1px solid #e7e7e7;
    padding: 1px;
  }
  body table.mxPopupMenu {
    border-collapse: collapse;
    margin: 0px;
  }
  body tr.mxPopupMenuItem {
    color: black;
    cursor: default;
  }
  body td.mxPopupMenuItem {
    padding: 6px 60px 6px 30px;
    font-family: Arial;
    font-size: 10pt;
  }
  body td.mxPopupMenuIcon {
    background-color: white;
    padding: 0px;
  }
  body tr.mxPopupMenuItemHover {
    background-color: #eeeeee;
    color: black;
  }
  table.mxPopupMenu hr {
    border-top: solid 1px #cccccc;
  }
  table.mxPopupMenu tr {
    font-size: 4pt;
  }
  .aside-data {
    padding: 10px;
    flex-flow: column wrap;
  }
  .table-row {
    .el-table__body tr:hover>td{
      cursor: pointer;
      // background-color: #c6cfdf!important;
    }

    .el-table__body tr.current-row>td{
      cursor: pointer;
      // background-color: #c6cfdf!important;
    }
  }
</style>
